﻿using System.Collections.Generic;
using VEGA.Algorithm.Elements;

namespace VEGA.Algorithm
{
    class Selector
    {
        public List<Individual> Input { get; set; }
        public List<Individual> Output { get; set; }

        private int _selectionSize = 50;

        public int SelectionSize
        {
            get { return _selectionSize; }
            set { _selectionSize = value; }
        }

        public void Run()
        {
            var goodPowerChildren = GetParentWithPowerFitness(Input);
            var goodPerformanceChildren = GetParentWithPerformanceFitness(Input);

            Output = new List<Individual>();
            Output.AddRange(goodPowerChildren);
            Output.AddRange(goodPerformanceChildren);

            Shuffle(Output);
        }

        private IEnumerable<Individual> GetParentWithPowerFitness(IEnumerable<Individual> parents)
        {
            var powerIndividuals = new List<Individual>(parents);

           // powerIndividuals.Sort(new IndividualPowerComperer());
            //var rez = powerIndividuals.GetRange(0, SelectionSize);

            var selectedParents = new List<Individual>();
            for (var i = 0; i < _selectionSize; i++)
            {
                double totalFitness = 0;
                foreach (var performanceIndividual in powerIndividuals)
                {
                    totalFitness += performanceIndividual.FitnessPower;
                }
                var value = totalFitness * RandomSingleton.Rand.NextDouble();
                double sum = 0;
                int index = 0;
                foreach (var individual in powerIndividuals)
                {
                    sum += individual.FitnessPower;
                    if (sum > value)
                    {
                        selectedParents.Add(individual);
                        break;
                    }
                    index++;
                }
                powerIndividuals.RemoveAt(index);
            }

            return powerIndividuals;
        }

        private IEnumerable<Individual> GetParentWithPerformanceFitness(IEnumerable<Individual> parents)
        {
            var performanceIndividuals = new List<Individual>(parents);

           // performanceIndividuals.Sort(new IndividualIpcComparison());
           // var rez = performanceIndividuals.GetRange(0, SelectionSize);
            
            var selectedParents = new List<Individual>();
            for (var i = 0; i < _selectionSize; i++)
            {
                double totalFitness = 0;
                foreach (var performanceIndividual in performanceIndividuals)
                {
                    totalFitness += performanceIndividual.FitnessIpc;
                }
                var value = totalFitness*RandomSingleton.Rand.NextDouble();
                double sum = 0;
                int index = 0;
                foreach (var individual in performanceIndividuals)
                {
                    sum += individual.FitnessIpc;
                    if (sum > value)
                    {
                        selectedParents.Add(individual);
                        break;
                    }
                    index++;
                }
                performanceIndividuals.RemoveAt(index);
            }

            return performanceIndividuals;
        }

        public static void Shuffle(List<Individual> list)
        {
            var rng = RandomSingleton.Rand;

            var n = list.Count;

            while (n > 1)
            {
                n--;
                var k = rng.Next(n + 1);
                var value = list[k];
                list[k] = list[n];
                list[n] = value;
            }
        }
    }
}
